/*
 * Copyright (C) 2010 Fred Barrie This program is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version. This program is distributed
 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details. You should have received
 * a copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package org.aergia.vinny.database.pojo;

import java.util.Calendar;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

import org.aergia.vinny.core.enums.TimeFrame;
import org.aergia.vinny.util.CollectionsUtil;
import org.aergia.vinny.util.DateUtil;
import org.w3c.dom.Element;

/**
 * @author fred
 */
@Entity
public class Service implements DatabasePojo {

	private boolean active;
	private boolean approved;
	private VinnyUser approvedBy;
	private String comment;
	private long duration;
	private Calendar endTime;
	private int id;
	private Location location;
	private ServiceType serviceType;
	private Skill skill;
	private Calendar startTime;
	private int timeFrame;
	private Volunteer volunteer;

	public Service() {
		// empty
	}

	/**
	 * @param scan
	 * @param endTime
	 */
	public Service(final Scan start, final Calendar endTime, final String comment) {
		this.startTime = start.getScanTime();
		this.endTime = endTime;
		this.comment = comment;
		this.active = true;
		this.approved = false;
		this.approvedBy = null;
		this.timeFrame = TimeFrame.SCAN.getValue();

		this.volunteer = start.getCard().getVolunteer();
		this.skill = CollectionsUtil.getFirst(this.volunteer.getSkills());
		this.duration = DateUtil.getDifference(this.startTime, this.endTime);
		this.serviceType = start.getServiceType();
		this.location = start.getLocation();
	}

	public Service(final Scan start, final Scan end) {
		this(start, end.getScanTime(), "");
	}

	public Service(final Volunteer volunteer, final ServiceType serviceType, final Skill skill, final Calendar date, final int duration,
			final TimeFrame timeFrame, final VinnyUser user) {
		this.active = true;
		this.approved = true;
		this.approvedBy = user;
		this.comment = "Manually entered by user " + this.approvedBy.getUserName() + ".";
		this.startTime = date;
		this.endTime = DateUtil.getInstance(this.startTime);
		this.endTime.add(Calendar.MINUTE, duration);
		this.skill = skill;
		this.volunteer = volunteer;
		this.duration = DateUtil.getDifference(this.startTime, this.endTime);
		this.serviceType = serviceType;
		this.timeFrame = timeFrame.getValue();
	}

	@Override
	public void attachAttributes(final Element element) {
		element.setAttribute("id", Integer.toString(this.getId()));
		element.setAttribute("active", Boolean.toString(this.isActive()));
		element.setAttribute("approved", Boolean.toString(this.isApproved()));
		if (this.getApprovedBy() != null) {
			element.setAttribute("approvedBy", Integer.toString(this.getApprovedBy().getId()));
		}
		if (this.getComment() != null) {
			element.setAttribute("comment", this.getComment());
		}
		element.setAttribute("duration", Long.toString(this.getDuration()));
		element.setAttribute("endTime", DateUtil.format(this.getEndTime()));
		if (this.getSkill() != null) {
			element.setAttribute("skill", Integer.toString(this.getSkill().getId()));
		}
		element.setAttribute("startTime", DateUtil.format(this.getStartTime()));
		element.setAttribute("volunteer", Integer.toString(this.getVolunteer().getId()));
		if (this.getServiceType() != null) {
			element.setAttribute("serviceType", Integer.toString(this.getServiceType().getId()));
		}
		element.setAttribute("timeFrame", this.getTimeFrameAsPojo().toString());
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Service)) {
			return false;
		}
		final Service other = (Service) obj;

		if (this.getTimeFrame() == 0) {

			if (this.getStartTime() == null) {
				if (other.getStartTime() != null) {
					return false;
				}
			} else if (!this.getStartTime().equals(other.getStartTime())) {
				return false;
			}
		} else {
			if (this.getTimeFrame() != other.getTimeFrame()) {
				return false;
			}
			if (this.getStartTime().get(Calendar.DAY_OF_YEAR) != other.getStartTime().get(Calendar.DAY_OF_YEAR)) {
				return false;
			}
			if (this.getDuration() != other.getDuration()) {
				return false;
			}
		}
		if (this.getVolunteer() == null) {
			if (other.getVolunteer() != null) {
				return false;
			}
		} else if (!this.getVolunteer().equals(other.getVolunteer())) {
			return false;
		}
		return true;
	}

	/**
	 * @return the approvedBy
	 */
	@ManyToOne
	public VinnyUser getApprovedBy() {
		return this.approvedBy;
	}

	/**
	 * @return the comment
	 */
	public String getComment() {
		return this.comment;
	}

	/**
	 * @return the duration
	 */
	public long getDuration() {
		return this.duration;
	}

	/**
	 * @return the endTime
	 */
	public Calendar getEndTime() {
		return this.endTime;
	}

	@Override
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public int getId() {
		return this.id;
	}

	/**
	 * @return the location
	 */
	public Location getLocation() {
		return this.location;
	}

	/**
	 * @return the serviceType
	 */
	@ManyToOne
	public ServiceType getServiceType() {
		return this.serviceType;
	}

	/**
	 * @return the skill
	 */
	@ManyToOne
	public Skill getSkill() {
		return this.skill;
	}

	/**
	 * @return the startTime
	 */
	public Calendar getStartTime() {
		return this.startTime;
	}

	/**
	 * @return
	 */
	public int getTimeFrame() {
		return this.timeFrame;
	}

	public TimeFrame getTimeFrameAsPojo() {
		return TimeFrame.valueOf(this.timeFrame);
	}

	/**
	 * @return the volunteer
	 */
	@ManyToOne
	public Volunteer getVolunteer() {
		return this.volunteer;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = (prime * result) + (this.getStartTime() == null ? 0 : this.getStartTime().hashCode());
		result = (prime * result) + (this.getVolunteer() == null ? 0 : this.getVolunteer().hashCode());
		result = (prime * result) + (this.getStartTime() == null ? 0 : this.getStartTime().hashCode());
		result = (prime * result) + (int) this.getDuration();
		result = (prime * result) + this.getTimeFrame();
		return result;
	}

	@Override
	public boolean isActive() {
		return this.active;
	}

	/**
	 * @return the approved
	 */
	public boolean isApproved() {
		return this.approved;
	}

	/**
	 * @param active
	 *            the active to set
	 */
	public void setActive(final boolean active) {
		this.active = active;
	}

	/**
	 * @param approved
	 *            the approved to set
	 */
	public void setApproved(final boolean approved) {
		this.approved = approved;
	}

	/**
	 * @param approvedBy
	 *            the approvedBy to set
	 */
	public void setApprovedBy(final VinnyUser approvedBy) {
		this.approvedBy = approvedBy;
	}

	/**
	 * @param comment
	 *            the comment to set
	 */
	public void setComment(final String comment) {
		this.comment = comment;
	}

	/**
	 * @param duration
	 *            the duration to set
	 */
	public void setDuration(final long duration) {
		this.duration = duration;
	}

	/**
	 * @param endTime
	 *            the endTime to set
	 */
	public void setEndTime(final Calendar endTime) {
		this.endTime = endTime;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(final int id) {
		this.id = id;
	}

	/**
	 * @param location
	 *            the location to set
	 */
	public void setLocation(final Location location) {
		this.location = location;
	}

	/**
	 * @param serviceType
	 *            the serviceType to set
	 */
	public void setServiceType(final ServiceType serviceType) {
		this.serviceType = serviceType;
	}

	/**
	 * @param skill
	 *            the skill to set
	 */
	public void setSkill(final Skill skill) {
		this.skill = skill;
	}

	/**
	 * @param startTime
	 *            the startTime to set
	 */
	public void setStartTime(final Calendar startTime) {
		this.startTime = startTime;
	}

	/**
	 * @param timeFrame
	 */
	public void setTimeFrame(final int timeFrame) {
		this.timeFrame = timeFrame;
	}

	/**
	 * @param volunteer
	 *            the volunteer to set
	 */
	public void setVolunteer(final Volunteer volunteer) {
		this.volunteer = volunteer;
	}

}
